package com.ace.lab.starter.factory;

import com.ace.lab.starter.config.ZookeeperProperties;
import com.ace.lab.starter.constant.ZookeeperPath;
import com.ace.lab.starter.utils.BeanFactoryHelper;
import com.ace.lab.starter.utils.RpcClassHelper;
import io.grpc.Deadline;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.NameResolverProvider;
import io.grpc.stub.AbstractStub;
import io.grpc.util.RoundRobinLoadBalancerFactory;
import org.springframework.beans.factory.FactoryBean;

import java.util.concurrent.TimeUnit;

public class RpcClientFactoryBean<T extends AbstractStub> implements FactoryBean {

    private Class<T> clientClass;
    private NameResolverProvider nameResolverProvider;
    private ZookeeperProperties zookeeperProperties;

    public RpcClientFactoryBean(Class<T> clientClass) {
        this.clientClass = clientClass;
    }

    @Override
    public T getObject() throws Exception {
        if (nameResolverProvider == null) {
            nameResolverProvider = BeanFactoryHelper.getBeanFactory().getBean(NameResolverProvider.class);
        }
        if (zookeeperProperties == null) {
            zookeeperProperties = BeanFactoryHelper.getBeanFactory().getBean(ZookeeperProperties.class);
        }
        ManagedChannel channel = ManagedChannelBuilder.forTarget(getTarget())
                .nameResolverFactory(nameResolverProvider)
                .loadBalancerFactory(RoundRobinLoadBalancerFactory.getInstance())
                .usePlaintext(true)
                .build();
        T stub = RpcClassHelper.getClientInstance(clientClass, channel);
        //config stub options
        stub.withDeadline(Deadline.after(200, TimeUnit.MILLISECONDS));
        return stub;
    }

    private String getTarget() {
        String serviceName = RpcClassHelper.genServiceName(clientClass);
        return "zookeeper://" + zookeeperProperties.getConnections() + ZookeeperPath.SERVICE_ROOT_PATH + serviceName;
    }

    @Override
    public Class<T> getObjectType() {
        return clientClass;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }

}
